﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Media;
using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System.Text;
using Microsoft;

namespace TrainTicketsRobot
{
    public partial class FrmMain : Form
    {
        public CookieContainer cookconReq = new CookieContainer();
        public Dictionary<string, string> dicStation;
        private Hashtable htSeatType;
        private const int i32InitInterval = 5000;
        private bool IsPlayBeep = true;
        private int PgmAccess;
        public bool StopSearch;
        public bool StopFinsh;
        private string strOrderPage = "";
        private string[] strsTrainInfo = new string[14];
        private Uri uriBase = new Uri("https://dynamic.12306.cn");
        private bool bIsLogin = false;
        private string resDir = "./res";
        private string soundFilePath = "./res/start.wav";
        private Cracker loginCracker = new Cracker();
        private Cracker orderCracker = new Cracker();
        private static int nSearchTimes = 0;
        private int nSearchIntev = 0;
        private int nLoginIntev = 0;
        private static int nOrderTimes = 0;
        private TrainInfo[] TrainInfoArray = null;
        private string strTrainNo = "";

        public FrmMain()
        {
            InitializeComponent();
        }

        private int DoAutoLogin() 
        {
            int ret = 0;
            try
            {
                this.getLoginPassCode(new Random(DateTime.Now.Millisecond).NextDouble().ToString());
                string strLoginPassCode = this.loginCracker.Read(new Bitmap(this.pbLoginPassCode.Image));
                if (strLoginPassCode == "") 
                {
                    return -4;
                }
                this.txtLoginPassCode.Text = strLoginPassCode;
                string strRtn = this.Login();
                if (strRtn.Contains("myOrderAction"))
                {
                    this.gbLogin.Text = "已登录";
                    this.gbLogin.Enabled = false;
                    this.gbSearch.Enabled = true;
                    this.bIsLogin = true;
                    this.txtLog.AppendText("登录成功，欢迎" + this.txtUserName.Text + "...\r\n");
                    return 0;
                }

                if (strRtn.Contains("请输入正确的验证码"))
                {
                    this.txtLog.AppendText("验证码错误，请重试……\r\n");
                    ret = -2;
                    goto error1;
                }
                if (strRtn.Contains("密码输入错误"))
                {
                    this.txtLog.AppendText("密码错误，请重试……\r\n");
                    ret = -3;
                    goto error1;
                }
            }
            catch (Exception exception)
            {
                this.txtLog.AppendText("错误信息：" + exception.Message + "……");
                ret = -1;
            }

        error1:
            return ret;
        }

        private int DoHandLogin()
        {
            int ret = 0;
            try
            {
                
                string strLoginPassCode = this.txtLoginPassCode.Text;
                if (strLoginPassCode == "")
                {
                    return -4;
                }
                this.txtLoginPassCode.Text = strLoginPassCode;
                string strRtn = this.Login();
                if (strRtn.Contains("myOrderAction"))
                {
                    this.gbLogin.Text = "已登录";
                    this.gbLogin.Enabled = false;
                    this.gbSearch.Enabled = true;
                    this.bIsLogin = true;
                    this.txtLog.AppendText("登录成功，欢迎" + this.txtUserName.Text + "...\r\n");
                    return 0;
                }

                if (strRtn.Contains("请输入正确的验证码"))
                {
                    this.txtLog.AppendText("验证码错误，请重试……\r\n");
                    ret = -2;
                    goto error1;
                }
                if (strRtn.Contains("密码输入错误"))
                {
                    this.txtLog.AppendText("密码错误，请重试……\r\n");
                    ret = -3;
                    goto error1;
                }
            }
            catch (Exception exception)
            {
                this.txtLog.AppendText("错误信息：" + exception.Message + "……");
                ret = -1;
            }

        error1:
            return ret;
        }

        private void RunLoginThead()
        {
            Thread.CurrentThread.IsBackground = true;
            int loginIntev = Convert.ToInt32(this.txtLoginIntev.Text);
            this.gbLogin.Enabled = false;
            if (DoHandLogin() < 0)
            {
                this.gbLogin.Enabled = true;
            }
        }

        private void btnLogin_Click(object sender, EventArgs e) 
        {
            
            try
            {
                Control.CheckForIllegalCrossThreadCalls = false;
                new Thread(new ThreadStart(this.RunLoginThead)).Start();
            }
            catch (Exception exception)
            {
                MessageBox.Show(WebBot.strProcessError(exception), "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void btnManaul_Click(object sender, EventArgs e)
        {
            this.PopIE();
        }

        private void btnOrder_Click(object sender, EventArgs e)
        {
        }

        private void btnReLogin_Click(object sender, EventArgs e)
        {
        }

        private void btnReLoginAndSearch_Click(object sender, EventArgs e)
        {
            if (this.checkInput())
            {
                try
                {
                    Control.CheckForIllegalCrossThreadCalls = false;
                    new Thread(new ThreadStart(this.DoLoginAndOrderTrainTicketsThread)).Start();
                }
                catch (Exception exception)
                {
                    MessageBox.Show(WebBot.strProcessError(exception), "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }
            }
        }

        private void btnStopPlay_Click(object sender, EventArgs e)
        {
            this.IsPlayBeep = false;
            this.btnStopPlay.Enabled = false;
        }

        private void btnStopSearch_Click(object sender, EventArgs e)
        {
            this.StopSearch = true;
            nSearchTimes = 0;
            nOrderTimes = 0;
            this.txtLog.AppendText("正在停止……\r\n最近一步的操作必须全部执行完毕方能停止……\r\n");
        }

        private bool checkInput()
        {
            string text = "";
            if (this.txtUserName.Text == "")
            {
                text = text + "用户名未输入\r\n";
            }
            if (this.txtPassword.Text == "")
            {
                text = text + "密码未输入\r\n";
            }
            if (this.txtLoginIntev.Text == "")
            {
                text = text + "登录间隔时间未输入\r\n";
            }
            Regex regex = new Regex("^[0-9]*$");
            if (!regex.IsMatch(this.txtLoginIntev.Text))
            {
                text = text + "登录间隔时间应该为整数\r\n";
            }
            if (this.txtFromStation.Text == "")
            {
                text = text + "发站未输入\r\n";
            }
            if (this.txtToStation.Text == "")
            {
                text = text + "到站未输入\r\n";
            }
            if (this.txtTrainCode.Text == "")
            {
                text = text + "车次未输入，如想订多趟车，请多开\r\n";
            }
            Regex regex2 = new Regex("^[A-Za-z0-9]+$");
            if (!regex2.IsMatch(this.txtTrainCode.Text))
            {
                text = text + "车次只能输入字母和数字，请以12306车票预订界面公布的车次为准\r\n";
            }
            if (this.txtSearchIntev.Text == "")
            {
                text = text + "检索间隔时间未输入\r\n";
            }
            if (!regex.IsMatch(this.txtSearchIntev.Text))
            {
                text = text + "检索间隔时间应该为整数\r\n";
            }
            if (this.cbSeatType.SelectedItem == null)
            {
                text = text + "席别未选择\r\n";
            }
            if (this.dgvInfo.Rows.Count <= 1)
            {
                text = text + "乘车人信息未输入\r\n";
            }
            if (text != "")
            {
                MessageBox.Show(text, "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }
            return true;
        }

        private int DoOrderTrainTickets() 
        {
            if (!this.RepeatLogin()) 
            {
                return -1;
            }

            this.InitTrainInfo();

            foreach (TrainInfo train in this.TrainInfoArray) 
            {
                string[] valueArry = train.value.Split('/');
                foreach(string v in valueArry)
                {
                    if (this.txtTrainCode.Text == v)
                    {
                        this.strTrainNo = train.id;
                    }
                }
            }

            return this.RepeatOrderTrain();
        }

        private void ResetResource() 
        {
            this.gbLogin.Enabled = false;
            this.gbSearch.Enabled = false;
            this.gbOrder.Enabled = false;
            this.btnReLoginAndSearch.Enabled = false;
            this.nSearchIntev = Convert.ToInt32(this.txtSearchIntev.Text) * 1000;
            this.nLoginIntev = Convert.ToInt32(this.txtLoginIntev.Text) * 1000;
            this.loginCracker = new Cracker();
            this.orderCracker = new Cracker();
            this.strOrderPage = "";
            this.strsTrainInfo = new string[14];
            nOrderTimes = 0;
            nSearchTimes = 0;
        }

        private void InitTrainInfo() 
        {
            try
            {
                if (this.TrainInfoArray != null)
                {
                    return;
                }

                Uri uri = new Uri(this.uriBase, "/otsweb/order/querySingleAction.do?method=queryststrainall");
                string strPostData = "date=" + this.dtpGoDate.Value.ToString("yyyy-MM-dd")
                    + "&fromstation=" + this.dicStation[this.txtFromStation.Text]
                    + "&tostation=" + this.dicStation[this.txtToStation.Text]
                    + "&starttime=" + HttpUtility.UrlEncode(this.cbGoTime.Text);
                string strJson = WebBot.ReadStream(WebBot.SendData(uri, strPostData, ref this.cookconReq));
                this.TrainInfoArray = TRConvert.ToTrainInfoArray(strJson);
            }
            catch 
            {
                return;
            }
        }

        private void DoLoginAndOrderTrainTicketsThread()
        {
            Thread.CurrentThread.IsBackground = true;
            this.StopSearch = false;
            this.StopFinsh = false;
            while (!this.StopSearch)
            {
                this.ResetResource();
                switch (this.DoOrderTrainTickets()) 
                {
                    case 1:
                    case 0://订票成功
                        this.PgmAccess = 999;
                        goto success;

                    case -1:
                        this.PgmAccess = 10;
                        break;

                    case -2:
                        this.PgmAccess = 10;
                        this.txtLog.AppendText("程序发生异常。\r\n");
                        break;

                    case -3:
                        this.PgmAccess = 10;
                        this.txtLog.AppendText("找不到" + this.cbSeatType.SelectedItem.ToString() + "，请重新选择。\r\n");
                        break;

                    case -10:
                        this.PgmAccess = 10;
                        goto stop;

                    case -20:
                        this.PgmAccess = 0;
                        this.bIsLogin = false;
                        this.txtLog.AppendText("检索异常，应该是登录太久被系统踢掉了！请重新登录！\r\n");
                        break;
                }

                Thread.Sleep(1000);
            }

        stop:
            this.resetForm();
            this.StopFinsh = true;
            this.txtLog.AppendText("手动停止成功。\r\n");
            return;

        success:
            this.resetForm();
            this.btnStopPlay.Enabled = true;
            new Thread(new ThreadStart(this.playBeep)).Start();
            return;
        }

        private void InitSystemRes() 
        {
            if (!Directory.Exists(this.resDir))
            {
                Directory.CreateDirectory(this.resDir);
            }
        }

        private void LoadFrmSeting() 
        {
            RobotConfig cfg = new RobotConfig();
            FrmMainConfig frmMainConfig = cfg.LoadConfig();
            if (frmMainConfig == null)
            {
                return;
            }

            this.txtUserName.Text = frmMainConfig.frmMainSetting.UserName;
            this.txtPassword.Text = frmMainConfig.frmMainSetting.UserPwd;
            this.txtLoginIntev.Text = Convert.ToString(frmMainConfig.frmMainSetting.LoginInterval);
            this.txtFromStation.Text = frmMainConfig.frmMainSetting.FromStation;
            this.txtToStation.Text = frmMainConfig.frmMainSetting.ToStation;
            this.dtpGoDate.Text = frmMainConfig.frmMainSetting.GoDate;
            this.cbGoTime.Text = frmMainConfig.frmMainSetting.GoTime;
            this.txtTrainCode.Text = frmMainConfig.frmMainSetting.TrainNo;
            this.txtSearchIntev.Text = Convert.ToString(frmMainConfig.frmMainSetting.SearchInterval);
            this.cbSeatType.Text = frmMainConfig.frmMainSetting.SetType;

            checkPassengerInfo();
            int pasgerCount = frmMainConfig.pasgerList.PassengerList.Length;
            for (int i = 0; i < pasgerCount; i++)
            {
                string PasgerName = frmMainConfig.pasgerList.PassengerList[i].PasgerName;
                string CardNumber = frmMainConfig.pasgerList.PassengerList[i].CardNumber;
                string MobilePhone = frmMainConfig.pasgerList.PassengerList[i].MobilePhone;
                DataGridViewRow dataGridViewRow = new DataGridViewRow();
                this.dgvInfo.Rows.Add(PasgerName, CardNumber, MobilePhone);
            }
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            this.htSeatType = new Hashtable();
            this.htSeatType.Add("硬座", "1");
            this.htSeatType.Add("无座", "1");
            this.htSeatType.Add("硬卧", "3");
            this.htSeatType.Add("软卧", "4");
            this.htSeatType.Add("一等软座", "7");
            this.htSeatType.Add("二等软座", "8");
            this.htSeatType.Add("高级软卧", "6");
            this.htSeatType.Add("商务座", "9");
            foreach (string str in this.htSeatType.Keys)
            {
                this.cbSeatType.Items.Add(str);
            }
            this.dtpGoDate.Value = DateTime.Now.AddDays(11.0);
            ToolTip tip = new ToolTip
            {
                InitialDelay = 500,
                ReshowDelay = 500
            };
            tip.SetToolTip(this.pbLoginPassCode, "点击后刷新验证码");
            tip.SetToolTip(this.pbOrderPassCode, "点击后刷新验证码");
            this.cbGoTime.SelectedIndex = 0;
            this.InitSystemRes();
            this.LoadFrmSeting();
        }

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            try
            {
                Control.CheckForIllegalCrossThreadCalls = false;
                new Thread(new ThreadStart(this.initLogin)).Start();
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message + "\r\n请重新运行程序。", "出错了，请重新运行程序", MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        public static List<Cookie> GetAllCookies(CookieContainer cc)
        {
            List<Cookie> list = new List<Cookie>();
            Hashtable hashtable = (Hashtable)cc.GetType().InvokeMember("m_domainTable", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, cc, new object[0]);
            foreach (object obj2 in hashtable.Values)
            {
                SortedList list2 = (SortedList)obj2.GetType().InvokeMember("m_list", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, obj2, new object[0]);
                foreach (CookieCollection cookies in list2.Values)
                {
                    foreach (Cookie cookie in cookies)
                    {
                        list.Add(cookie);
                    }
                }
            }
            return list;
        }

        private void getLoginPassCode(string strRandom)
        {
            try
            {
                string relativeUri = "/otsweb/passCodeAction.do?rand=sjrand";
                if (strRandom != "")
                {
                    relativeUri = relativeUri + "&" + strRandom;
                }
                Uri uri = new Uri(this.uriBase, relativeUri);
                HttpWebResponse response = WebBot.SendData(uri, ref this.cookconReq);
                this.pbLoginPassCode.Image = new Bitmap(response.GetResponseStream());
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

        private void getOrderPassCode(string strRandom)
        {
            try
            {
                string relativeUri = "/otsweb/passCodeAction.do?rand=randp";
                if (strRandom != "")
                {
                    relativeUri = relativeUri + "&" + strRandom;
                }
                Uri uri = new Uri(this.uriBase, relativeUri);
                HttpWebResponse response = WebBot.SendData(uri, ref this.cookconReq);
                Stream RepStream = response.GetResponseStream();
                this.pbOrderPassCode.Image = new Bitmap(RepStream);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

        private string GetPageMessage(string strRtn)
        {
            Regex regex = new Regex("var message = \"(.+)?\";\r\n *?var messageShow");
            return regex.Match(strRtn).Groups[1].Value;
        }

        private Dictionary<string, string> getStationDic()
        {
            Dictionary<string, string> dictionary2;
            try
            {
                Uri uri = new Uri(this.uriBase, "/otsweb/js/common/station_name.js?version=1.9");
                string[] strArray = WebBot.ReadStream(WebBot.SendData(uri, ref this.cookconReq)).Replace("';", "").Split(new char[] { '@' });
                Dictionary<string, string> dictionary = new Dictionary<string, string>();
                for (int i = 1; i < strArray.Length; i++)
                {
                    string[] strArray2 = strArray[i].Split(new char[] { '|' });
                    dictionary.Add(strArray2[1], strArray2[2]);
                }
                dictionary2 = dictionary;
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return dictionary2;
        }
        
        private void initLogin()
        {
            Thread.CurrentThread.IsBackground = true;
            bool flag = false;
            while (!flag)
            {
                try
                {
                    this.txtLog.AppendText("正在初始化……");
                    Thread.Sleep(0x1388);
                    Uri uri = new Uri(this.uriBase, "/otsweb/");
                    WebBot.ReadStream(WebBot.SendData(uri, ref this.cookconReq));
                    this.dicStation = this.getStationDic();
                    flag = true;
                    this.txtLog.AppendText("初始化成功！\r\n");
                    this.gbLogin.Enabled = true;
                    this.gbSearch.Enabled = true;
                    this.gbOrder.Enabled = true;
                    this.gbButton.Enabled = true;
                    continue;
                    
                }
                catch (Exception exception)
                {
                    this.txtLog.AppendText(exception.Message + "\r\n");
                    continue;
                }
            }
        }

        [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool InternetSetCookie(string lpszUrlName, 
            string lbszCookieName, string lpszCookieData);

        private string getLoginRandCode(string strJson)
        {
            LoginRand loginRand = new LoginRand(strJson);
            return loginRand.loginRand;
        }
        private string Login()
        {
            string str2;
            try
            {
                Uri loginAysnSuggestUri = new Uri(this.uriBase, "/otsweb/loginAction.do?method=loginAysnSuggest");
                string loginRand = getLoginRandCode(
                        WebBot.ReadStream(
                            WebBot.SendPostData(loginAysnSuggestUri, "", ref this.cookconReq)
                        )
                    );
                Uri uri = new Uri(this.uriBase, "/otsweb/loginAction.do?method=login");
                string strPostData = "loginRand=" + loginRand;
                strPostData += "&refundLogin=N&refundFlag=Y";
                strPostData += "&loginUser.user_name=" + this.txtUserName.Text;
                strPostData += "&nameErrorFocus=";
                strPostData += "&user.password=" + this.txtPassword.Text;
                strPostData += "&passwordErrorFocus=";
                strPostData += "&randCode=" + this.txtLoginPassCode.Text;
                strPostData += "&randErrorFocus=focus";

                str2 = WebBot.ReadStream(
                        WebBot.SendData(uri, strPostData, ref this.cookconReq)
                    );
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return str2;
        }

        private void checkPassengerInfo() 
        {
            for (int i = 0; i < (this.dgvInfo.Rows.Count - 1); i++)
            {
                DataGridViewRow dataGridViewRow = this.dgvInfo.Rows[i];
                for (int j = 0; j < this.dgvInfo.Columns.Count; j++)
                {
                    if (dataGridViewRow.Cells[j].Value == null)
                    {
                        dataGridViewRow.Cells[j].Value = "";
                    }
                }
                if (((dataGridViewRow.Cells[0].Value.ToString() == "") && (dataGridViewRow.Cells[1].Value.ToString() == "")) && (dataGridViewRow.Cells[2].Value.ToString() == ""))
                {
                    this.dgvInfo.Rows.Remove(dataGridViewRow);
                }
            }
        }

        private string getOrderTicketsPostData(string orderPassCode, string trainGoDate,
                    string setType, string leftTicketStr)
        {
            string strPostData = "";
            Regex regex1 = new Regex("org.apache.struts.taglib.html.TOKEN\" value=\"(.+)?\">");
            string org_apache_struts_taglib_html_TOKEN = regex1.Match(this.strOrderPage).Groups[1].Value;

            Regex regex3 = new Regex("textfield\".*\\s+value=\"(.+)?\"\\s");
            string textfield = regex3.Match(this.strOrderPage).Groups[1].Value;

            Regex regex4 = new Regex("orderRequest.seat_type_code\" value=\"(.*)?\"\\s");
            string seat_type_code = regex4.Match(this.strOrderPage).Groups[1].Value;

            Regex regex6 = new Regex("orderRequest.ticket_type_order_num\" value=\"(.*)?\"\\s");
            string ticket_type_order_num = regex6.Match(this.strOrderPage).Groups[1].Value;

            strPostData = "org.apache.struts.taglib.html.TOKEN="
                + org_apache_struts_taglib_html_TOKEN
                + "&leftTicketStr=" + leftTicketStr
                + "&textfield=" + HttpUtility.UrlEncode(textfield)
                + "&orderRequest.train_date=" + trainGoDate
                + "&orderRequest.train_no=" + this.strsTrainInfo[3]
                + "&orderRequest.station_train_code=" + this.strsTrainInfo[0]
                + "&orderRequest.from_station_telecode=" + this.strsTrainInfo[4]
                + "&orderRequest.to_station_telecode=" + this.strsTrainInfo[5]
                + "&orderRequest.seat_type_code=" + seat_type_code
                + "&orderRequest.ticket_type_order_num=" + ticket_type_order_num
                + "&orderRequest.bed_level_order_num=000000000000000000000000000000"
                + "&orderRequest.start_time=" + HttpUtility.UrlEncode(this.strsTrainInfo[2])
                + "&orderRequest.end_time=" + HttpUtility.UrlEncode(this.strsTrainInfo[6])
                + "&orderRequest.from_station_name=" + HttpUtility.UrlEncode(this.strsTrainInfo[7])
                + "&orderRequest.to_station_name=" + HttpUtility.UrlEncode(this.strsTrainInfo[8])
                + "&orderRequest.cancel_flag=1" + "&orderRequest.id_mode=Y";

            checkPassengerInfo();
            string strPassenger = "";
            for (int i = 0; i < (this.dgvInfo.Rows.Count - 1); i++)
            {
                DataGridViewRow dataGridViewRow = this.dgvInfo.Rows[i];
                string passengerName = dataGridViewRow.Cells[0].Value.ToString();
                string cardNo = dataGridViewRow.Cells[1].Value.ToString();
                string mobileno = dataGridViewRow.Cells[2].Value.ToString();
                strPassenger += "&passengerTickets="
                    + HttpUtility.UrlEncode(
                            string.Concat(new object[] { 
                                                setType,
                                                ",0",
                                                ",1,",  
                                                passengerName, 
                                                ",1,",  
                                                cardNo,
                                                ",",
                                                mobileno, 
                                                ",N"
                                            }
                                )
                        );
                strPassenger += "&passenger_" + Convert.ToString(i + 1) + "_seat=" + setType;
                strPassenger += "&passenger_" + Convert.ToString(i + 1) + "_ticket=1";
                strPassenger += "&passenger_" + Convert.ToString(i + 1) + "_name=" + HttpUtility.UrlEncode(passengerName);
                strPassenger += "&passenger_" + Convert.ToString(i + 1) + "_cardtype=1";
                strPassenger += "&passenger_" + Convert.ToString(i + 1) + "_cardno=" + cardNo;
                strPassenger += "&passenger_" + Convert.ToString(i + 1) + "_mobileno=" + mobileno;
            }
            strPostData += strPassenger;
            strPostData = (strPostData + "&randCode=" + orderPassCode) + "&orderRequest.reserve_flag=A&tFlag=dc";

            return strPostData;
        }

        private OrderWaiteTimeRet OrderWaiteTimePage()
        {
            string strRtn = "";
            int waiteTime = 0;
            int tryIntev = 500; //0.5s
            Uri uri = new Uri(this.uriBase, "/otsweb/order/myOrderAction.do?method=queryOrderWaitTime&tourFlag=dc");
            do
            {
                strRtn = WebBot.ReadStream(WebBot.SendData(uri, ref this.cookconReq));
                OrderWaitTime orderWaitTime = TRConvert.ToOrderWaiteTime(strRtn);
                if (orderWaitTime == null) 
                {
                    this.txtLog.AppendText("订票发生异常，重试中......\r\n");
                    continue;
                }

                waiteTime = orderWaitTime.waitTime;

                if (waiteTime == 0 || waiteTime == -1)
                {
                    this.txtLog.AppendText("订票成功！请尽快付款！\r\n");
                    return new OrderWaiteTimeRet(0, orderWaitTime.orderId);
                }

                if (waiteTime == -2)
                {
                    this.txtLog.AppendText("出票失败，" + orderWaitTime.msg + "，请重新订票！\r\n");
                    return new OrderWaiteTimeRet(-1, "");
                }

                if (waiteTime == -3)
                {
                    this.txtLog.AppendText("订单已经被取消！\r\n");
                    return new OrderWaiteTimeRet(-1, "");
                }

                if (waiteTime == -4)
                {
                    this.txtLog.AppendText("正在处理中....\r\n");
                }

                if (waiteTime > 0)
                {
                    this.txtLog.AppendText("排队中......排队数【" + orderWaitTime.waitCount + "】  预计时间【" + orderWaitTime.waitTime + "】 不过这时间不怎么靠谱 ╮(╯▽╰)╭\r\n");
                }
                else 
                {
                    this.txtLog.AppendText("奇怪的状态码 [" + orderWaitTime.waitTime + "]....\r\n");
                }

                Thread.Sleep(tryIntev);

            } while (!this.StopSearch);

            return new OrderWaiteTimeRet(-10, "");
        }

        private string PayOrderPage(string orderId, string strPostData)
        {
            Uri uri = new Uri(this.uriBase, "/otsweb/order/confirmPassengerAction.do?method=payOrder&orderSequence_no=" + orderId);
            string strRtn = WebBot.ReadStream(WebBot.SendData(uri, strPostData,ref this.cookconReq));
            return strRtn;
        }

        private int Order()
        {
            string pageMessage = "";
            string strRtn = "";
            do 
            {
                try 
                {
                    
                    this.getOrderPassCode(new Random(DateTime.Now.Millisecond).NextDouble().ToString());
                    string orderPassCode = this.orderCracker.Read(new Bitmap(this.pbOrderPassCode.Image));
                    this.txtOrderPassCode.Text = orderPassCode;
                    string trainGoDate = this.dtpGoDate.Value.ToString("yyyy-MM-dd");
                    string setType = this.htSeatType[this.cbSeatType.SelectedItem.ToString()].ToString();
                    Regex regex2 = new Regex("leftTicketStr\".*\\s+value=\"(.+)?\" />");
                    string leftTicketStr = regex2.Match(this.strOrderPage).Groups[1].Value;
                    string strPostData = getOrderTicketsPostData(orderPassCode, 
                        trainGoDate, setType, leftTicketStr);

                    Uri uri1 = new Uri(this.uriBase, "/otsweb/order/confirmPassengerAction.do?method=checkOrderInfo&rand=" + orderPassCode);
                    strRtn = WebBot.ReadStream(WebBot.SendData(uri1, strPostData, ref this.cookconReq));
                    CheckOrderInfo checkOrderInfo = new CheckOrderInfo(strRtn);
                    if (checkOrderInfo.checkHuimd == "N" || checkOrderInfo.errMsg != "Y")
                    {
                        this.txtLog.AppendText("订票失败，" + checkOrderInfo.msg + checkOrderInfo.errMsg + "\r\n");
                        continue;
                    }
                    Uri uri2 = new Uri(this.uriBase, 
                                "/otsweb/order/confirmPassengerAction.do?method=getQueueCount"
                                + "&train_date=" + trainGoDate 
                                + "&train_no=" + this.strsTrainInfo[3] 
                                + "&station=" + this.strsTrainInfo[0]
                                + "&seat=" + setType
                                + "&from=" + this.strsTrainInfo[4]
                                + "&to=" + this.strsTrainInfo[5]
                                + "&ticket=" + leftTicketStr
                            );
                    
                    strRtn = WebBot.ReadStream(WebBot.SendData(uri2, ref this.cookconReq));

                    Uri uri3 = new Uri(this.uriBase, "/otsweb/order/confirmPassengerAction.do?method=confirmSingleForQueue");
                    strRtn = WebBot.ReadStream(WebBot.SendData(uri3, strPostData, ref this.cookconReq));

                    OrderWaiteTimeRet OrderRet = OrderWaiteTimePage();
                    string orderId = OrderRet.OrderID;
                    int ret = OrderRet.RetValue;
                    if (ret <= -1) 
                    {
                        return -1;
                    }
                    strRtn = PayOrderPage(orderId, strPostData);
                    pageMessage = this.GetPageMessage(strRtn);
                    if ((pageMessage != "") || (!strRtn.Contains("successTicketNum") && !pageMessage.Contains("您还有未处理的订单")))
                    {
                        this.txtLog.AppendText("\r\n" + this.GetPageMessage(strRtn) + "\r\n");
                        this.txtLog.AppendText("订票失败，正在重试……第" + ++nOrderTimes + "次\r\n");
                        this.strOrderPage = strRtn;
                    }
                    else
                    {
                        this.txtLog.AppendText("★★★★订票至少已经部分成功，正在弹出IE并登录★★★★\r\n");
                        this.PopIE();
                    }
                    if ((pageMessage == "") && (strRtn.Contains("successTicketNum") || pageMessage.Contains("您还有未处理的订单")))
                    {
                        return 0;
                    }
                }
                catch
                {
                    return -2;
                }

            } while (!this.StopSearch);

            return -10;
        }

        private void pbLoginPassCode_Click(object sender, EventArgs e)
        {
            try
            {
                this.getLoginPassCode(new Random(DateTime.Now.Millisecond).NextDouble().ToString());
            }
            catch (Exception exception)
            {
                MessageBox.Show(WebBot.strProcessError(exception), "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void playBeep()
        {
            Thread.CurrentThread.IsBackground = true;
            while (this.IsPlayBeep)
            {
                TRSoundPlayer.PlaySound(Application.StartupPath + this.soundFilePath);
                Thread.Sleep(10000);
            }
        }

        private void PopIE()
        {
            string lpszUrlName = "https://dynamic.12306.cn/otsweb/";
            foreach (Cookie cookie in GetAllCookies(this.cookconReq))
            {
                string str2;
                if (cookie.Name == "JSESSIONID")
                {
                    str2 = cookie.Value + ";Path=/otsweb;expires=Sun,22-Feb-2099 00:00:00 GMT";
                }
                else
                {
                    str2 = cookie.Value + ";path=/;expires=Sun,22-Feb-2099 00:00:00 GMT";
                }
                InternetSetCookie(lpszUrlName, cookie.Name, str2);
            }
            Process.Start("IEXPLORE.EXE", lpszUrlName);
        }

        private int PreOrderTrain()
        {
            this.strOrderPage = "";
            try
            {
                string strFromStation = this.txtFromStation.Text;
                string strToStation = this.txtToStation.Text;
                Uri uri = new Uri(this.uriBase, "/otsweb/order/querySingleAction.do?method=submutOrderRequest");
                string strPostData = "station_train_code=" + this.strsTrainInfo[0] 
                    + "&train_date=" + this.dtpGoDate.Value.ToString("yyyy-MM-dd") 
                    + "&seattype_num=&from_station_telecode=" + this.strsTrainInfo[4] 
                    + "&to_station_telecode=" + this.strsTrainInfo[5]
                    + "&include_student=00&from_station_telecode_name=" + HttpUtility.UrlEncode(strFromStation)
                    + "&to_station_telecode_name=" + HttpUtility.UrlEncode(strToStation)
                    + "&round_train_date=" + this.dtpGoDate.Value.ToString("yyyy-MM-dd") 
                    + "&round_start_time_str=00%3A00--24%3A00&single_round_type=1"
                    + "&train_pass_type=QB&train_class_arr=QB%23D%23Z%23T%23K%23QT%23"
                    + "&start_time_str=" + HttpUtility.UrlEncode(this.cbGoTime.Text) 
                    + "&lishi=" + HttpUtility.UrlEncode(this.strsTrainInfo[1])
                    + "&train_start_time=" + HttpUtility.UrlEncode(this.strsTrainInfo[2])
                    + "&trainno4=" + this.strsTrainInfo[3] 
                    + "&arrive_time=" + HttpUtility.UrlEncode(this.strsTrainInfo[6])
                    + "&from_station_name=" + HttpUtility.UrlEncode(this.strsTrainInfo[7])
                    + "&to_station_name=" + HttpUtility.UrlEncode(this.strsTrainInfo[8])
                    + "&from_station_no=" + this.strsTrainInfo[9]
                    + "&to_station_no=" + this.strsTrainInfo[10]
                    + "&ypInfoDetail=" + this.strsTrainInfo[11]
                    + "&mmStr=" + this.strsTrainInfo[12]
                    + "&locationCode=" + this.strsTrainInfo[13];

                HttpWebResponse respRtn = WebBot.SendData(uri, strPostData, ref this.cookconReq);
                this.strOrderPage = WebBot.ReadStream(respRtn);
                string strcookie = this.cookconReq.ToString();
            }
            catch (Exception exception)
            {
                this.txtLog.AppendText(exception.Message + "\r\n");
                return -1;
            }
            return ((this.strOrderPage == "") ? -1 : 0);
        }

        private bool RepeatLogin()
        {
            if (this.bIsLogin)
            {
                return true;
            }
            int ret = 0;
            this.gbLogin.Enabled = false;
            do
            {
                ret = DoAutoLogin();
                if (ret <= -3) 
                {
                    break;
                } 
                else if (ret < 0)
                {
                    Thread.Sleep(this.nLoginIntev);
                }

            } while (!this.StopSearch && !this.bIsLogin);

            bool bRet = true;
            if (this.StopSearch || !this.bIsLogin)
            {
                bRet = false;
                this.gbLogin.Enabled = true;
            }
            
            return bRet;
        }

        private int RepeatSearchTrain() 
        {
            while (!this.StopSearch)
            {
                try
                {
                    this.txtLog.AppendText("第" + ++nSearchTimes + "次检索车次……");
                    int ret = this.SearchTrainCode();
                    if (ret < -1)
                    {// 登录时间太久被系统提出
                        return ret;
                    }
                    else if (ret < 0) 
                    {// 预订车次查找失败，继续查找
                        this.txtLog.AppendText("找不到" + this.txtTrainCode.Text.ToUpper() + "次列车，或该车次没有票。如果车次填写错误，请关闭程序重新输入。\r\n");
                        Thread.Sleep(this.nSearchIntev);
                    }

                    if ((this.strsTrainInfo[0] != null) && (this.strsTrainInfo[0] != ""))
                    {// 预订车次查找成功
                        return 0;
                    }
                }
                catch (Exception exception2)
                {
                    //发生异常休眠后继续
                    this.txtLog.AppendText(exception2.Message + "\r\n");
                    Thread.Sleep(this.nSearchIntev);
                }
            }
            // 手动停止
            return -10;
        }

        private int RepeatOrderTrain()
        {
            try
            {
                this.IsPlayBeep = true;
                this.StopSearch = false;
                int ret = 0;
                do {
                    ret = RepeatSearchTrain();
                    if (ret <= -10) 
                    {// 被系统踢出或者手动停止，直接退出循环
                        return ret;
                    }
                    else if (ret < 0) 
                    {// 查找预订车次失败
                        continue;
                    }
                    this.txtLog.AppendText("检索到" + this.strsTrainInfo[0] + "次列车\r\n");
                    this.txtLog.AppendText("尝试进入车辆预订页面……");

                    if ((this.PreOrderTrain() != 0)
                        || (!this.strOrderPage.Contains("org.apache.struts.taglib.html.TOKEN"))) 
                    {
                        this.txtLog.AppendText("进入车辆预订页面失败！\r\n");
                        Thread.Sleep(this.nSearchIntev);
                        continue;
                    }

                    if (this.strOrderPage.Contains("您还有未处理的订单"))
                    {
                        this.txtLog.AppendText("您还有未处理的订单......\r\n");
                        return 1;
                    }
                    
                    this.txtLog.AppendText("进入车辆预订页面成功。\r\n");
                    Regex regex = new Regex("<td>(" + this.cbSeatType.SelectedItem.ToString() + @"\(\d*\.\d*元\)(.*)?)</td>");
                    this.txtLog.AppendText("准备预订：" + this.cbSeatType.SelectedItem.ToString() );

                    Match ticketMatch = regex.Match(this.strOrderPage);
                    string strTicketInfo = ticketMatch.Groups[1].Value;
                    string strHaveTicket = ticketMatch.Groups[2].Value;
                    if (strTicketInfo == "" || strHaveTicket == "无票")
                    {
                        this.txtLog.AppendText("-->没有" + this.cbSeatType.SelectedItem.ToString() + "，正在重新查询……\r\n");
                        Thread.Sleep(this.nSearchIntev);
                        continue;
                    }
                    this.txtLog.AppendText("-->票务信息：" + strTicketInfo + "\r\n");

                    ret = this.Order();
                    if (ret <= -10 || ret >= 0)
                    {// 手动停止或者订票成功，退出循环
                        return ret;
                    }
                } while (!this.StopSearch);
                
                return -10;
            }
            catch (Exception exception4)
            {
                this.txtLog.AppendText("订票发生异常: " + exception4.Message + "\r\n");
                return -2;
            }
        }

        private void resetForm()
        {
            switch (this.PgmAccess)
            {
                case 0:
                    this.gbLogin.Enabled = true;
                    this.gbSearch.Enabled = true;
                    this.gbOrder.Enabled = true;
                    this.pbLoginPassCode.Image = null;
                    this.pbOrderPassCode.Image = null;
                    this.txtLoginPassCode.Text = "";
                    this.txtOrderPassCode.Text = "";
                    this.pbLoginPassCode_Click(null, null);
                    this.btnReLoginAndSearch.Enabled = true;
                    break;

                case 10:
                    this.gbSearch.Enabled = true;
                    this.gbOrder.Enabled = true;
                    this.btnReLoginAndSearch.Enabled = true;
                    break;
            }
        }

        private int SearchTrainCode()
        {
            try
            {
                Uri uri = new Uri(this.uriBase, "/otsweb/order/querySingleAction.do?method=queryLeftTicket&orderRequest.train_date=" + this.dtpGoDate.Value.ToString("yyyy-MM-dd")
                    + "&orderRequest.from_station_telecode=" + this.dicStation[this.txtFromStation.Text]
                    + "&orderRequest.to_station_telecode=" + this.dicStation[this.txtToStation.Text]
                    + "&orderRequest.train_no=" + this.strTrainNo
                    + "&trainPassType=QB&trainClass=QB%23D%23Z%23T%23K%23QT%23&includeStudent=00&seatTypeAndNum=&orderRequest.start_time_str=" 
                    + HttpUtility.UrlEncode(this.cbGoTime.Text));

                string input = WebBot.ReadStream(WebBot.SendData(uri, ref this.cookconReq, true));
                this.strsTrainInfo = new string[14];
                if (input == "-10")
                {
                    return -20;
                }



                string searchTainCode = this.txtTrainCode.Text.ToUpper();
                Regex regex = new Regex(@"onclick=javascript:getSelected\('(.*?)'\)");
                foreach (Match match in regex.Matches(input))
                {
                    string tmpTrainCode = match.Groups[1].Value.Split(new char[] { '#' })[0];
                    if (tmpTrainCode == searchTainCode)
                    {
                        this.strsTrainInfo = match.Groups[1].Value.Split(new char[] { '#' });
                        return 0;
                    }
                }
                return -1;
            }
            catch (Exception exception)
            {
                this.txtLog.AppendText("SearchTrainCode Exception: " + exception.Message + "\r\n");
                return -1;
            }
        }

        private void txtLog_TextChanged(object sender, EventArgs e)
        {
            this.txtLog.ScrollToCaret();
        }

        private delegate string MethodDelegate();

        private void SaveCfgButton_Click(object sender, EventArgs e)
        {
            RobotConfig cfg = new RobotConfig();
            FrmMainConfig frmMainConfig = new FrmMainConfig();
            frmMainConfig.frmMainSetting.UserName = this.txtUserName.Text;
            frmMainConfig.frmMainSetting.UserPwd = this.txtPassword.Text;
            frmMainConfig.frmMainSetting.LoginInterval = Convert.ToInt32(this.txtLoginIntev.Text);
            frmMainConfig.frmMainSetting.FromStation = this.txtFromStation.Text;
            frmMainConfig.frmMainSetting.ToStation = this.txtToStation.Text;
            frmMainConfig.frmMainSetting.GoDate = this.dtpGoDate.Text;
            frmMainConfig.frmMainSetting.GoTime = this.cbGoTime.Text;
            frmMainConfig.frmMainSetting.TrainNo = this.txtTrainCode.Text;
            frmMainConfig.frmMainSetting.SearchInterval = Convert.ToInt32(this.txtSearchIntev.Text);
            frmMainConfig.frmMainSetting.SetType = this.cbSeatType.Text;
            
            checkPassengerInfo();
            int pasgerCount = this.dgvInfo.Rows.Count - 1;
            frmMainConfig.pasgerList.PassengerList = new Passenger[pasgerCount];
            for (int i = 0; i < pasgerCount; i++)
            {
                DataGridViewRow dataGridViewRow = this.dgvInfo.Rows[i];
                string passengerName = dataGridViewRow.Cells[0].Value.ToString();
                string cardNo = dataGridViewRow.Cells[1].Value.ToString();
                string mobileno = dataGridViewRow.Cells[2].Value.ToString();
                Passenger pasger = new Passenger();
                pasger.PasgerName = passengerName;
                pasger.CardNumber = cardNo;
                pasger.MobilePhone = mobileno;
                frmMainConfig.pasgerList.PassengerList[i] = pasger;
            }
            cfg.SaveConfig(frmMainConfig);
            this.txtLog.AppendText("保存配置文件成功...\r\n");
        }

        private void TestButton_Click(object sender, EventArgs e)
        {
            TRTester Tester = new TRTester();
            Tester.Run();
        }

        private void TestButton_Click_1(object sender, EventArgs e)
        {
            TRTester Tester = new TRTester();
            Tester.Run();

            this.getLoginPassCode(new Random(DateTime.Now.Millisecond).NextDouble().ToString());
            this.txtLoginPassCode.Text = AspriseOCR.OCRBitmap(new Bitmap(this.pbLoginPassCode.Image));
        }

        private void pbLoginPassCode_Click_1(object sender, EventArgs e)
        {
            this.getLoginPassCode(new Random(DateTime.Now.Millisecond).NextDouble().ToString());
        }

        private void pbOrderPassCode_Click(object sender, EventArgs e)
        {
            this.getOrderPassCode(new Random(DateTime.Now.Millisecond).NextDouble().ToString());
        }
    }
}
